#  utils.rb
#
#  This file is part of myvnet.
#
#  Copyright (C) 2008  Filipe David Borba Manana,  fdmanana@gmail.com
#
#  myvnet is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  myvnet is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with myvnet.  If not, see <http://www.gnu.org/licenses/>.


require 'socket'


module Utils
  
  # header bits/ioctls.h
  SIOCGIFHWADDR = 0x89_27    # get hardware address
  SIOCGIFADDR   = 0x89_15    # get PA address
  SIOCGIFMTU    = 0x89_21    # get MTU
  
  
  module_function
  

  # === Synopsis
  # 
  #   Utils.iface_mtu(interface)
  #   
  # === Args
  # 
  # A network interface name (as a String). For example: eth0, lo.
  # 
  # === Return
  # 
  # The MTU (Maximum Transfer Unit) of the network interface, or nil
  # if the network interface doesn't exist.
  # 
  # === Description
  # 
  # Returns the MTU of a specified network interface.
  #    
  def iface_mtu(interface)
    mtu = nil
    
    begin
      sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)    
      buff = interface.dup

      # second parameter is of type struct ifreq defined in
      # header net/if.h
      # 
      # first field of the struct is a 16 bytes string with 
      # the name of a network interface, second field is a 
      # union containing struct sockaddr (header sys/socket.h)
      # fields and other fields of basic types (int, char, etc).
      # 
      sock.ioctl(SIOCGIFMTU, buff)
      mtu = (buff[16..20].unpack 'i')[0]
    rescue
    ensure
      sock.close if sock
    end

    mtu
  end
 
  
  # === Synopsis
  # 
  #   Utils.iface_hwaddr(interface)
  #   
  # === Args
  # 
  # A network interface name (as a String). For example: eth0, lo.
  # 
  # === Return
  # 
  # The hardware address of the network interface, or nil if the
  # network interface doesn't exist.
  # 
  # === Description
  # 
  # Returns the hardware address of a specified network interface.
  #  
  def iface_hwaddr(interface)
    hwaddr = nil
    
    begin
      sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)    
      buff = interface.dup

      sock.ioctl(SIOCGIFHWADDR, buff)
      hwaddr = buff[18..24].unpack 'C6'
      hwaddr = ("%02x:%02x:%02x:%02x:%02x:%02x" % hwaddr)
    rescue
    ensure
      sock.close if sock
    end
    
    hwaddr
  end  
  
  
  # === Synopsis
  # 
  #   Utils.hexdump(stream)
  #   
  # === Args
  # 
  # A byte stream, either as a String or as an Array.
  # 
  # === Return
  # 
  # An hexdump, as a String, of the given byte stream. Each line 
  # of the hex dump displays at most 16 bytes, represented as two
  # digit hexadecimal values and separated by spaces.
  # 
  # === Description
  # 
  # Returns an hexdump of a given byte stream.
  #  
  def hexdump(stream)
    case stream
      when String
      when Array
        stream = stream.pack 'C*'
      else
        return ''
    end
    
    dump = ""
    offset = -16
    cnt = 16
    
    stream.each_byte do |b|
      if cnt == 16
        offset += 16
        cnt = 0
        dump << "\n" << ("%04X" % offset) << '  '
      end
      
      dump << ("%02X" % b) << ' '
      cnt += 1
    end
    
    dump.chomp ' '
    dump << "\n"
  end
      
end
